import {PlayerColor, PieceState} from './types'
import {BoardCenter} from '../constants/constants'
import {Utils} from '../utils'

export class Piece {
  colIndex = 0
  rowIndex = 0
  id: string
  visible = true
  color: PlayerColor = 'Unknown'
  state: PieceState = 'Unactivated'
  obliqueGroup: string
  neighbors: number[][]

  constructor(visible: boolean, x: number, y: number, group: string, neighbors) {
    this.visible = visible
    this.colIndex = x
    this.rowIndex = y
    this.obliqueGroup = group
    this.id = `${x}_${y}`
    this.neighbors = neighbors
  }

  static getSay3Pieces(p: Piece, pieces: Piece[][]): Piece[][] {
    const results = []
    results.push(pieces[p.rowIndex].filter(x => {
      return x.visible && (p.rowIndex !== BoardCenter ||
        (p.colIndex < BoardCenter && x.colIndex < BoardCenter) ||
        (p.colIndex > BoardCenter && x.colIndex > BoardCenter))
    }))

    const cols = []
    for (let i = 0; i < pieces.length; i++) {
      const row = pieces[i]
      if (!row[p.colIndex].visible) {
        continue
      }
      if (p.colIndex !== BoardCenter ||
        (p.rowIndex < BoardCenter && i < BoardCenter) ||
        (p.rowIndex > BoardCenter && i > BoardCenter)) {
        cols.push(row[p.colIndex])
      }
    }
    results.push(cols)

    if (p.obliqueGroup) {
      results.push(Utils.flat(pieces).filter(x => x.obliqueGroup === p.obliqueGroup))
    }

    return results
  }

  static hasColors(pieces: Piece[], color: PlayerColor, count: number) {
    return pieces.filter(x => x.color == color).length >= count
  }
  static hasActivatedColors(pieces: Piece[], color: PlayerColor, count: number) {
    return pieces.filter(x => x.color == color && x.state==='Activated').length >= count
  }

  static getNeighbors(p: Piece, pieces: Piece[][], canMoveIn): Piece[] {
    const neighbors = p.neighbors.map(x => pieces[x[1]][x[0]])
    return canMoveIn ? neighbors.filter(x => ['Deleted', 'Unactivated'].includes(x.state)) : neighbors
  }

  canSay3(pieces: Piece[][], color: PlayerColor, steps = 0): boolean {
    const copied = Utils.clone(pieces)
    const mock = copied[this.rowIndex][this.colIndex]
    const canSay3 = (p: Piece) => Piece.getSay3Pieces(p, copied).some(row => row.every(x => x.color === color && x.state === 'Activated'))

    switch (steps) {
      case 0:
        mock.color = color
        mock.state = 'Activated'
        return canSay3(this)
      case 1:
        mock.color = 'Unknown'
        mock.state = 'Deleted'
        for (let p of Piece.getNeighbors(mock, copied, true)) {
          p.color = color
          p.state = 'Activated'
          if (canSay3(p)) {
            return true
          }
        }
        return false
      case 2:
        mock.color = 'Unknown'
        mock.state = 'Deleted'
        for (let p of Utils.flat(Piece.getNeighbors(mock,copied, true).map(n => {
          return Piece.getNeighbors(n, copied, true)
        }))) {
          p.color = color
          p.state = 'Activated'
          if (canSay3(p)) {
            return true
          }
        }
        return false
    }
  }
}
